package com.komon.object.response.bodyIO;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;

import com.komon.constant.Configuration;

/**
 * Chunked-Body   = 	*chunk
                        last-chunk
                        trailer
                        CRLF
       chunk          = chunk-size [ chunk-extension ] CRLF
                        chunk-data CRLF
       chunk-size     = 1*HEX
       last-chunk     = 1*("0") [ chunk-extension ] CRLF
       chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
       chunk-ext-name = token
       chunk-ext-val  = token | quoted-string
       chunk-data     = chunk-size(OCTET)
       trailer        = *(entity-header CRLF)
	
	Since the chunked encoding must be the last encoding of the message, so don't let this class inherit the FilterOutputSteam
	other body encoding output stream should inherit the FilterOutputStream
	
 * @author timon.zhang
 *
 */
//TODO concurrent
public class ChunkedResponseBodyOutputStream extends OutputStream {
	//buffer
	//TODO: support change buffer dynamicly?
	protected volatile int bufferSize = Configuration.DEFAULT_RESP_BUFFER_SIZE;
	protected volatile int bufferOffset = 0;
	protected byte[] buffer = new byte[bufferSize];
	
	private final OutputStream socketOutputStream;
	
	public ChunkedResponseBodyOutputStream(OutputStream socketOutputStream) {
		this.socketOutputStream = socketOutputStream;	
	}
	
	@Override
	public void flush() throws IOException {
		flushBuffer();
		socketOutputStream.flush();
	}
	
	@Override
	
	public void write(int b) throws IOException {
		if (bufferOffset >= bufferSize) {//need to flush buffer
			flushBuffer();
		}
		buffer[bufferOffset++] = (byte) b;
	}
	
	private void flushBuffer() throws UnsupportedEncodingException, IOException {
		socketOutputStream.write( (Integer.toHexString(bufferOffset) + " " ).getBytes(Configuration.DEFAULT_RESP_BODY_ENCODING));
		socketOutputStream.write('\r'); socketOutputStream.write('\n');
		//write chunk date
		socketOutputStream.write(buffer, 0, bufferOffset);
		//clear buffer
		bufferOffset = 0;
	}

	
	/* (non-Javadoc)
	 * @see java.io.OutputStream#close()
	 */
	/**
	 * ouput last chunk
	 */
	@Override
	public void close() throws IOException {
		socketOutputStream.write('\r'); socketOutputStream.write('\n');
		socketOutputStream.write( ("0" + " ").getBytes(Configuration.DEFAULT_RESP_BODY_ENCODING));
		socketOutputStream.write('\r'); socketOutputStream.write('\n');
		flush();
	}
	
}
